﻿<!DOCTYPE HTML>
<html lang="zh">
<head>
<title>循环读取 - 语法 &amp; 使用 | AutoHotkey v2</title>
<meta name="description" content="The 循环读取 statement retrieves the lines in a text file, one at a time." />
<meta name="ahk:equiv-v1" content="commands/LoopReadFile.htm" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<link href="../static/theme.css" rel="stylesheet" type="text/css" />
<script src="../static/content.js" type="text/javascript"></script>
<script type="text/javascript">$(function(){0<=window.navigator.userAgent.toLowerCase().indexOf("ucbrowser")&&CaoNiMaDeUc()})</script>
</head>
<body>

<h1>循环读取</h1>

<p>检索文本文件中的行, 每次一行.</p>

<pre class="Syntax"><span class="func">循环读取</span> InputFile <span class="optional">, OutputFile</span></pre>
<h2 id="Parameters">参数</h2>
<dl>

  <dt>InputFile</dt>
  <dd>
    <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
    <p>需要在循环中读取其内容的文本文件的名称, 如果未指定绝对路径, 则假定在 <a href="../Variables.htm#WorkingDir">内_工作目录</a> 中. 文件的行结束符可以是回车和换行符(`r`n), 也可以只是换行符(`n), 或只是回车(`r).</p>
  </dd>

  <dt>OutputFile</dt>
  <dd>
      <p>类型: <a href="../Concepts.htm#strings">字符串</a></p>
      <p>在循环期间保持打开的文件的名称, 如果未指定绝对路径, 则假定在 <a href="../Variables.htm#WorkingDir">内_工作目录</a> 中.</p>
      <p>在循环的主体内, 使用 <a href="FileAppend.htm">附加</a> 函数, 不带 <em>Filename</em> 参数(即省略它) 来追加到这个特殊的文件. 以这种方式追加到一个文件比使用 2 个参数模式的 <a href="FileAppend.htm">附加</a> 执行地更好, 因为每次操作时不需要关闭文件和再重新打开. 如果需要的话, 记得在文本后加入换行符(`n) 或回车符和换行符(`r`n).</p>
      <p>如果没有向文件写入任何内容, 文件就不会被打开. 如果循环执行零迭代或从未调用 <a href="FileAppend.htm">附加</a>, 就会发生这种情况.</p>
      <p><strong>选项</strong>: 行末(EOL) 转换模式和输出文件编码取决于在 <a href="FileAppend.htm">附加</a> 的首次调用中传递的选项(即省略 <em>Filename</em> 的首次调用). 随后的调用会忽略 <em>Options</em> 参数. 默认情况下不执行 EOL 转换; 也就是说, 除非存在 <code>"`n"</code> 选项, 否则换行符(`n) 将按原样写入.</p>
      <p><strong>标准输出(stdout)</strong>:指定 <em>OutputFile</em> 为星号(*) 可以把 <a href="FileAppend.htm">附加</a> 写入的任何文本发送到标准输出(stdout). 尽管这样的输出可以重定向到文件, 指向另一个 EXE 的管道或被<a href="_ErrorStdOut.htm">高级文本编辑器</a>捕获, 然而它不会出现在运行它的命令提示符中. 有关详情, 请参阅 <a href="FileAppend.htm">附加</a>.</p>
  </dd>

</dl>

<h2 id="Remarks">备注</h2>
<p>当您想对包含在文本文件中的内容逐行进行操作时, 文件读取循环很有用. 在整个操作过程中, 文件是打开的, 以避免每次都要重新扫描以找到下一行.</p>
<p id="LoopReadLine">内置变量 <strong>内_循环读取行</strong> 存在于任何文件读取循环中. 它包含当前行的内容, 不包括回车和标志行结束的换行符(`r`n). 如果一个内部的文件读取循环被一个外部的文件读取循环所包围, 那么最内部循环的文件行将优先.</p>
<p>读取长度为 65,534 个字符的行. 如果行的长度超过了这个长度, 其剩余的字符将在下一个循环迭代时被读取.</p>
<p><a href="StrSplit.htm">分割字符串</a> 或<a href="LoopParse.htm">解析循环</a>通常用于文件读取循环中, 以解析从 <em>InputFile</em> 中获取的每一行的内容. 例如, 如果 <em>InputFile</em> 的每一行都是一系列以 tab 分隔的字段, 那么这些字段可以像这个例子一样单独检索:</p>
<pre>循环读取, "C:\Database Export.txt"
{
    循环转换, 内_循环读取行, 内_跳格
    {
        信息框 "Field number " 内_循环次数 " is " 内_循环属性 "."
    }
}</pre>
<p>要加载整个文件内容到变量中, 请使用 <a href="FileRead.htm">读文件</a>, 因为它比循环执行的更好(尤其对于大文件).</p>
<p>要同时打开多个文件, 请使用 <a href="FileOpen.htm">打开文件</a>.</p>
<p>请参阅 <a href="Loop.htm">循环</a> 了解关于<a href="Block.htm">区块</a>, <a href="Break.htm">跳出</a>, <a href="Continue.htm">跳过</a> 和 内_循环次数 变量(其存在于各种类型的循环中) 的相关信息.</p>
<p>在不存在字节顺序标记时要控制如何解码文件, 请使用 <a href="FileEncoding.htm">设置文件编码</a>.</p>

<h2 id="Related">相关</h2>
<p><a href="FileEncoding.htm">设置文件编码</a>, <a href="FileOpen.htm">打开文件</a>/<a href="../objects/File.htm">File 对象</a>, <a href="FileRead.htm">读文件</a>, <a href="FileAppend.htm">附加</a>, <a href="Sort.htm">排序</a>, <a href="Loop.htm">循环</a>, <a href="Break.htm">跳出</a>, <a href="Continue.htm">跳过</a>, <a href="Block.htm">区块</a>, <a href="FileSetAttrib.htm">文件设置属性</a>, <a href="FileSetTime.htm">文件设置时间</a></p>

<h2 id="Examples">示例</h2>
<div class="ex" id="ExFileAppend">
<p><a href="#ExFileAppend">#1</a>: 只有首个文件中包含单词 FAMILY 的那些行才会写入第二个文件中. 取消注释首行可以覆盖而不是追加到任何现有的文件中.</p>
<pre><em>;文件删除 "C:\Docs\Family Addresses.txt"</em>

循环读取, "C:\Docs\Address List.txt", "C:\Docs\Family Addresses.txt"
{
    如果 查找(内_循环读取行, "family")
        附加(内_循环读取行 "`n")
}</pre>
</div>

<div class="ex" id="ExLastLine">
<p><a href="#ExLastLine">#2</a>: 获取文本文件的最后一行.</p>
<pre>循环读取, "C:\Log File.txt"
    last_line := 内_循环读取行  <em>; 当循环结束时, 这里会保持最后一行的内容.</em></pre>
</div>

<div class="ex" id="ExURL">
<p><a href="#ExURL">#3</a>: 尝试从文本或 HTML 文件中提取所有 FTP 和 HTTP URL 的有效脚本:</p>
<pre>
SourceFile := 文件选择框(3,, "Pick a text or HTML file to analyze.")
如果 SourceFile = ""
    返回  <em>; 此时将退出.</em>

分割路径 SourceFile,, SourceFilePath,, SourceFileNoExt
DestFile := SourceFilePath "\" SourceFileNoExt " Extracted Links.txt"

如果 文件是否存在(DestFile)
{
    Result := 信息框("Overwrite the existing links file? Press No to append to it.`n`nFILE: " DestFile,, 4)
    如果 Result = "Yes"
        文件删除 DestFile
}

LinkCount := 0
循环读取, SourceFile, DestFile
{
    URLSearch(内_循环读取行)
}
信息框 LinkCount ' links were found and written to "' DestFile '".'
返回


URLSearch(URLSearchString)
{
    <em>; 由于在一些 URL(网址) 中内嵌有其他的 URL, 所以用这种特殊的方法进行处理:
    ; 找到最左边的起始位置:</em>
    URLStart := 0  <em>; 设置起始默认值.</em>
    遍历 URLPrefix in ["https://", "http://", "ftp://", "www."]
    {
        ThisPos := 查找(URLSearchString, URLPrefix)
        如果 !ThisPos  <em>; 此前缀被取消资格.</em>
            跳过
        如果 !URLStart
            URLStart := ThisPos
        否则 <em>; URLStart 里面有一个有效的位置, 所以要和 ThisPos 比较一下.</em>
        {
            如果 ThisPos &amp;&amp; ThisPos &lt; URLStart
                URLStart := ThisPos
        }
    }

    如果 !URLStart  <em>; 在 URLSearchString 中不存在 URL.</em>
        返回

    <em>; 否则, 提取该 URL:</em>
    URL := 截取字符串(URLSearchString, URLStart)  <em>; 忽略开始/无效部分.</em>
    循环转换, URL, " `t&lt;&gt;"  <em>; 找到首个空格, tab 或尖括号(如果有).</em>
    {
        URL := 内_循环属性
        跳出  <em>; 即仅执行一次循环来获取首个 "片段".</em>
    }
    <em>; 如果上面的循环因为没有找到结尾字符而导致迭代次数为零,
    ; 那么 URL 变量的内容保持不变.

    ; 如果 URL 以双引号结束, 那么移除它. 暂时使用 StringReplace, 不过注意
    ; 双引号似乎可以合法存在于 URL 中, 所以这样做
    ; 可能破坏它们:</em>
    URLCleansed := 字符串替换(URL, '"')
    附加 URLCleansed "`n"
    global LinkCount += 1

    <em>; 看看当前行中是否含有其他 URL:</em>
    CharactersToOmit := 字符串长度(URL)
    CharactersToOmit += URLStart
    URLSearchString := 截取字符串(URLSearchString, CharactersToOmit)
    
    <em>; 到自身的递归调用:</em>
    URLSearch(URLSearchString)
}
</pre>
</div>

</body>
</html>